package org.dreamwork.tools.simulator.connector.managed;

import org.dreamwork.db.ITransaction;
import org.dreamwork.db.SQLite;
import org.dreamwork.tools.simulator.connector.data.DummyVariable;
import org.dreamwork.util.StringUtil;

import javax.annotation.Resource;

import java.io.IOException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.function.Function;

import static org.dreamwork.tools.simulator.connector.data.VariableType.TEXT;

@Resource
public class DummyVariableService {
    @Resource
    private SQLite sqlite;

    public void create (DummyVariable var) {
        if (StringUtil.isEmpty (var.getName ())) {
            throw new NullPointerException ();
        }

        if (sqlite.exists (DummyVariable.class, var.getName ())) {
            throw new RuntimeException ("variable [" + var.getName () + "] already exists.");
        }

        if (var.getType () == null) {
            var.setType (TEXT);
        }
        adjustRange (var);
        sqlite.save (var, false);
    }

    public void update (DummyVariable var) {
        if (StringUtil.isEmpty (var.getName ())) {
            throw new NullPointerException ();
        }

        if (!sqlite.exists (DummyVariable.class, var.getName ())) {
            throw new RuntimeException ("variable[" + var.getName () + "] not found.");
        }

        ITransaction tx = null;
        try {
            tx = sqlite.beginTransaction ();
            tx.delete (var);
            tx.save (var, false);
            tx.commit ();
        } catch (Exception ex) {
            try {
                if (tx != null) tx.rollback ();
            } catch (SQLException ignore) {}
            throw new RuntimeException (ex);
        } finally {
            if (tx != null) {
                try {
                    tx.close ();
                } catch (IOException ignore) {}
            }
        }
    }

    public void delete (DummyVariable var) {
        sqlite.delete (var);
    }

    public List<DummyVariable> list () {
        return sqlite.get (DummyVariable.class, null, "name");
    }

    private void adjustRange (DummyVariable var) {
        switch (var.getType ()) {
            case INT:
                swap (var, Integer::parseInt);
                break;

            case FLOAT:
                swap (var, Float::parseFloat);
                break;

            case TIMESTAMP:
                swap (var, Long::parseLong);
                break;

            case DATE:
                swap (var, value -> {
                    try {
                        return new SimpleDateFormat ("yyyy-MM-dd").parse (value);
                    } catch (ParseException ex) {
                        throw new RuntimeException (ex);
                    }
                });
                break;

            case DATETIME:
                swap (var, value -> {
                    try {
                        return new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss").parse (value);
                    } catch (ParseException ex) {
                        throw new RuntimeException (ex);
                    }
                });
                break;
        }
    }

    private<T extends Comparable<T>> void swap (DummyVariable var, Function<String, T> func) {
        T min = func.apply (var.getLow ()), max = func.apply (var.getHigh ());
        if (min.compareTo (max) > 0) {
            T tmp = min;
            min = max;
            max = tmp;

            var.setLow (String.valueOf (min));
            var.setHigh (String.valueOf (max));
        }
    }
}